package cn.example.demo.modules.house.recommend.engine;

import cn.example.demo.modules.house.entity.House;
import cn.example.demo.modules.house.mapper.HouseMapper;
import cn.example.demo.modules.house.recommend.DataDimensionEncoder;
import cn.example.demo.modules.house.service.IHouseService;
import cn.example.demo.modules.house.service.IHouseTypeService;
import cn.example.demo.modules.house.service.IRegionService;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.apache.mahout.cf.taste.impl.recommender.GenericRecommendedItem;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Description: 基于内容的推荐引擎（核心算法实现）
 *
 * @author Lzx
 * @create 2025/3/22 16:24
 */
@Component
@Slf4j
public class ContentBasedRecommenderEngine {
    @Autowired
    private IHouseService houseService;
    @Autowired
    private HouseMapper houseMapper;
    @Autowired
    private IHouseTypeService houseTypeService;
    @Autowired
    private IRegionService regionService;
    @Autowired
    private DataDimensionEncoder dataDimensionEncoder;

    // 构建特征向量
    private double[] buildFeatureVector(House house) {
        return new double[]{
                house.getCost().doubleValue() / 1000.0,          // 价格（千元单位）
                dataDimensionEncoder.encodeHouseType(house.getHouseType()),
                dataDimensionEncoder.encodeRegion(house.getRegionId()),
                (house.getStarMark() != null ? house.getStarMark() : 3.0) / 5.0
        };
    }

    // 计算余弦相似度
    private double cosineSimilarity(double[] v1, double[] v2) {
        double dotProduct = 0.0;
        double normA = 0.0;
        double normB = 0.0;
        for (int i = 0; i < v1.length; i++) {
            dotProduct += v1[i] * v2[i];
            normA += Math.pow(v1[i], 2);
            normB += Math.pow(v2[i], 2);
        }
        return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
    }

    public List<RecommendedItem> recommend(Integer userId, int topN) {
        log.error("当前处理的用户ID:{}", userId);
        // TODO-lzx 可能需要统计每个房源的综合评分，这里暂时使用默认值
        List<House> userHistory = houseService.getUserHistoryHouseList(userId);
        if (ObjectUtil.isEmpty(userHistory)) {
            return new ArrayList<>();
        }
        List<House> candidates = houseMapper.selectList(Wrappers.<House>lambdaQuery().notIn(House::getId, userHistory.stream().map(House::getId).collect(Collectors.toList())));
        Map<String, Double> scores = new HashMap<>();
        for (House historyHouse : userHistory) {
            double[] historyVec = buildFeatureVector(historyHouse);
            for (House candidate : candidates) {
                double[] candidateVec = buildFeatureVector(candidate);
                double sim = cosineSimilarity(historyVec, candidateVec);
                scores.merge(candidate.getId(), sim, Double::sum);
            }
        }
        return scores.entrySet().stream()
                .sorted(Map.Entry.<String, Double>comparingByValue().reversed())
                .limit(topN)
                .map(e -> new GenericRecommendedItem(Long.parseLong(e.getKey()), e.getValue().floatValue()))
                .collect(Collectors.toList());
    }
}
